﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CoreDB.Extensions
{
    /// <summary>
    /// 
    /// </summary>
    public static class EnumExtension
    {       
        /// <summary>
        /// 根据描述字符串和指定枚举类型获得对应的枚举变量。
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="description">解析的描述字符串</param>
        /// <returns>结果枚举变量</returns>
        public static T GetEnumByDescription<T>(this string description) where T : struct
        {
            var result = typeof(T).GetFields().FirstOrDefault(f => f.IsLiteral && f.GetDescriptionByFieldInfo() == description);
            return result == null ? default(T) : (T)Enum.Parse(typeof(T), result.Name);
        }
        /// <summary>
        /// 获得枚举类型中所有可能的值上的Decription特性描述字符串的集合。
        /// 即获取所有枚举项的Description
        /// </summary>
        /// <param name="enType">指定的枚举类型</param>
        /// <param name="containName">如果某枚举可能值上没有定义Description特性，是否返回该值的名称</param>
        /// <returns>描述字符串列表</returns>
        public static List<string> GetDescriptions(this Type enType, bool containName = true)
        {
            if (!enType.IsEnum)
                throw new ArgumentException("指定的类型不是枚举类型", nameof(enType));
            return enType.GetFields().Where(f => f.IsLiteral).Select(f => GetDescriptionByFieldInfo(f, containName)).ToList<string>();
        }
        /// <summary>
        /// 获得枚举变量所属枚举类型中所有可能的值上的Decription特性描述字符串的集合。
        /// </summary>
        /// <param name="en">指定的枚举变量</param>
        /// <param name="containName">如果某枚举可能值上没有定义Description特性，是否返回该值的名称</param>
        /// <returns>描述字符串列表</returns>
        public static List<string> GetDescriptions(this Enum en, bool containName = true)
        {
            return en.GetType().GetDescriptions(containName);
        }
        /// <summary>
        /// 获得枚举变量中定义该值处的Description特性描述的字符串。
        /// </summary>
        /// <param name="en">指定的枚举变量</param>
        /// <param name="containName">若该枚举值上没有定义Description特性，是否返回该值的名称</param>
        /// <returns>描述字符串</returns>
        public static string GetDescription(this Enum en, bool containName = true)
        {
            return GetDescriptionByFieldInfo(en.GetType().GetField(en.ToString()), containName);
        }
        #region private
        private static string GetDescriptionByFieldInfo(this FieldInfo fieldInfo, bool containName = true)
        {
            if (!fieldInfo.IsDefined(typeof(DescriptionAttribute), false))
                return containName ? fieldInfo.Name : string.Empty;
            return fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false).Cast<DescriptionAttribute>().First().Description;
        }
        #endregion
    }
}
